use crate::synway_call::{
	context::{covert_to_hangup_reason, ShChannelState},
	device::{get_called_id, get_caller_id, pending_reason},
};
use base_data::channel::{
	event::ChannelEvent, Channel, ChannelCallDirection, ChannelState, CommandMsg, OriginateChannel,
};
use std::{
	ffi::{c_int, c_uint, c_ushort},
	sync::OnceLock,
};
use tokio::sync::mpsc;
use tools::{global_defin::tokio_runtime::get_rt, ResultEx};
use tracing::{debug, error, info, span, trace, warn, Level};

use super::{
	context::ShEvent,
	device::{hangup_channel, originate, ShEventInfo},
};

pub(crate) static MANAGER: OnceLock<Manager> = OnceLock::new();
///用来接收消息并实际操作三汇板卡的
pub(crate) struct Manager {
	count: usize,
	handle_create: Box<dyn Fn(Channel) + Send + Sync + 'static>,
	///这个做为一个保存,发给Manager的发送者,每有一个呼入创建,拿一个此的副本
	to_switch: mpsc::Sender<CommandMsg>,
	device_to_switch: mpsc::Sender<ShEventInfo>,
}

impl Manager {
	pub fn new(
		handler_count: usize,
		handle_create: Box<dyn Fn(Channel) + Send + Sync + 'static>,
		to_switch: mpsc::Sender<CommandMsg>,
		device_to_switch: mpsc::Sender<ShEventInfo>,
	) -> Self {
		Self {
			count: handler_count,
			handle_create,
			to_switch,
			device_to_switch,
		}
	}

	pub(crate) async fn running(
		&self,
		mut from_handler: mpsc::Receiver<CommandMsg>,
		mut from_device: mpsc::Receiver<ShEventInfo>,
	) {
		let span = span!(Level::ERROR, "synway");
		let _guard = span.enter();

		info!("synway设备管理器启动.");
		let mut senders = vec![None; self.count];

		loop {
			tokio::select! {
				msg = from_handler.recv() => {
					if let Some(msg) = msg {
						if let Err(e) = handle_command_msg(&mut senders,msg) {
							error!("处理业务发来命令失败,{}",e);
						}
					} else {
						warn!("所有发送端退出,结束");
						return;
					}
				}
				msg =  from_device.recv() => {
					if let Some(msg) = msg {
						if let Err(e) = handle_device_event(&mut senders, msg).await {
							error!("处理板卡发来事件失败,{}",e);
						}
				 } else {
					 warn!("所有发送端退出,结束");
					 return;
				 }
				}
			}
		}
	}
}

///实际处理设备发来事件的方法
async fn handle_device_event(
	senders: &mut Vec<Option<tokio::sync::mpsc::Sender<ChannelEvent>>>,
	msg: ShEventInfo,
) -> ResultEx<()> {
	debug!("处理设备发来事件.{msg:?}.用户id:{}", msg.user);
	let manager = manager();

	match msg.event {
		ShEvent::EChgChState => {
			handle_ch_change(manager, senders, msg.n_reference as u32, msg.dw_param).await;
		}

		//TODO 接下来实现其他相关事件
		_ => error!("未实现,{:?}", msg.event),
	};

	Ok(())
}

///处理业务发来控制设备的命令
fn handle_command_msg(
	senders: &mut Vec<Option<tokio::sync::mpsc::Sender<ChannelEvent>>>,
	msg: CommandMsg,
) -> ResultEx<()> {
	match msg {
		CommandMsg::Originate(m) => {
			let ch_id = originate(&m.caller_num, &m.called_num)?;
			let (sender, from_switch) = mpsc::channel(256);
			let channel = OriginateChannel {
				id: ch_id,
				to_switch: manager().to_switch.clone(),
				from_switch,
			};
			senders[ch_id as usize] = Some(sender);

			send_to_business(
				senders,
				m.master_ch_id,
				ChannelEvent::ChannelOriginate(channel),
			);
			//要向远端发一个连接事件..
		}
		CommandMsg::Ringing => todo!(),
		CommandMsg::PreAnswer => todo!(),
		CommandMsg::PlayBell(_) => todo!(),
		CommandMsg::StopPlayBell => todo!(),
		CommandMsg::AnswerCall(_) => todo!(),
		CommandMsg::HangupChannel(ch_id, _) | CommandMsg::KillChannel(ch_id) => {
			hangup_channel(ch_id)?;
		}
		CommandMsg::BridgeChannel(..) => todo!(),
		CommandMsg::SetVar => todo!(),
		CommandMsg::StartRecordSound(..) => todo!(),
		CommandMsg::SendDtmf(_, _) => todo!(),
		CommandMsg::StopRecordSound => todo!(),
		CommandMsg::PlayBellList(_) => todo!(),
	};

	Ok(())
}

///此方法为板卡的回调函数...当板卡有事件发生时此方法被调用
///
#[no_mangle]
pub extern "C" fn CallBackFun(
	w_event: c_ushort,
	n_reference: c_int,
	dw_param: c_uint,
	dw_user: c_uint,
) -> c_int {
	//此方法由C语言调用,并在单独c的线程当中执行.
	//这里开始接收事件并处理...
	debug!(
		"收到板卡消息...event:{w_event}.nReference:{n_reference},dwParam:{dw_param},dwUser:{dw_user}"
	);

	//从这里调用
	get_rt().spawn(async move {
		let msg = ShEventInfo {
			event: (w_event as i32).into(),
			user: dw_user,
			n_reference,
			dw_param,
		};

		if let Err(e) = manager().device_to_switch.send(msg).await {
			error!("发送命令至synway manager失败:{}", e);
		}
	});

	//返回永远为0..表示成功
	0
}

fn manager() -> &'static Manager {
	MANAGER
		.get()
		.expect("获取板卡管理器失败.需要先调用init_synway()方法")
}

///通道状态改变的处理事件
#[inline]
async fn handle_ch_change(
	manager: &Manager,
	senders: &mut Vec<Option<tokio::sync::mpsc::Sender<ChannelEvent>>>,
	ch_id: u32,
	param: u32,
) {
	let old_state: ShChannelState = ((param >> 16) as i32).into();
	let now_state: ShChannelState = ((param & 0xffff) as i32).into();
	trace!("通道 {ch_id} 发生状态变化: {old_state} -> {now_state}");

	match now_state {
		ShChannelState::SCallRinging => {
			let (sender, from_switch) = mpsc::channel(256);
			let channel = Channel {
				id: ch_id,
				state: ChannelState::CallIn,
				direction: ChannelCallDirection::InBound,
				caller_num: get_caller_id(ch_id),
				dest_num: get_called_id(ch_id),
				to_switch: manager.to_switch.clone(),
				from_switch,
			};

			//将创建好的通道,一个保存,另一个调用业务逻辑方法.准备接收后续消息
			senders[ch_id as usize] = Some(sender);
			(manager.handle_create)(channel);
		}
		ShChannelState::SCallTalking => {
			send_to_business(
				senders,
				ch_id,
				ChannelEvent::ChannelCallState(ch_id, ChannelState::Answered),
			);
			send_to_business(senders, ch_id, ChannelEvent::ChannelAnswer(ch_id));
		}
		ShChannelState::SCallPending => {
			send_to_business(
				senders,
				ch_id,
				ChannelEvent::ChannelCallState(ch_id, ChannelState::Hangup),
			);

			let reason = pending_reason(ch_id);
			send_to_business(
				senders,
				ch_id,
				ChannelEvent::ChannelHangup(ch_id,covert_to_hangup_reason(reason)),
			);
		}
		ShChannelState::SCallStandby => match old_state {
			//当有活动时认为是挂断,其他不进行处理
			ShChannelState::SCallTalking
			| ShChannelState::SCallRinging
			| ShChannelState::SCallPickuped
			| ShChannelState::SCallWaitRemotePickup
			| ShChannelState::SIsupWaitRlc
			| ShChannelState::SCallPending => {
				send_to_business(
					senders,
					ch_id,
					ChannelEvent::ChannelCallState(ch_id, ChannelState::Down),
				);
			}
			_ => return,
		},
		_ => return,
	}
}

#[inline]
fn send_to_business(
	senders: &Vec<Option<tokio::sync::mpsc::Sender<ChannelEvent>>>,
	ch_id: u32,
	event: ChannelEvent,
) {
	if let Some(sender) = senders[ch_id as usize].as_ref() {
		if let Err(e) = sender.try_send(event) {
			error!("发送到业务处理逻辑失败..ch:{ch_id},e:{e}.");
		}
	} else {
		error!("获取到sender对象失败..ch:{ch_id}")
	}
}
